<template>
  <div class="list beauty-scroll">
    <div class="list-item" v-for="(item,index) in virtual_data" :key="index" :style="'top: '+item.top+'px;height:'+item.height+'px;'">
      <a-flex align="center">
        {{item.name}}
      </a-flex>
    </div>
    <div class="placeholder" :style="'height: '+ placeholder_height +'px;'"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue"

// 获取数据列表
const list_data = []
for (let i = 1; i <= 5000; i++){
  list_data.push({
    key: i,
    name: `列表 ${i}`,
  })
}

// 设置实际虚拟模块数量
const num = 50
// 当前渲染区域的高度
let list_total_height = 0
// 设置初始化 item 数据
const virtual_data = ref([])
// 设置 list_item_height
const list_item_height = 63
// 设置占位高度
const placeholder_height = ref(0)
// 存储滚动数据，用于滚动方向判断
let scrollTop = 0
let scrollTop_old = 0
// 设置滑动方向
let direction;
// 滚动function
const scroll_func = (event) => {
  scrollTop = event.srcElement.scrollTop
  // console.log(scrollTop);
  // 确定滑动方向
  if (scrollTop >= scrollTop_old) {
    direction = 'down'
  } else {
    direction = 'up'
  }
  scrollTop_old = scrollTop
  // console.log(direction);
  // 计算信息
  const section = Math.floor(scrollTop / list_total_height) // 移动过了多少个区间
  const index = Math.floor((scrollTop - list_total_height * section) / list_item_height)  //当前scrollTop在该区间的位置下标值
  // 生成新的virtual_data
  virtual_data.value = getVirtualData(section, index)
}

onMounted(() => {
  // 计算占位高度
  list_total_height = list_item_height * num
  placeholder_height.value = list_data.length * list_item_height - list_total_height
  // 配置virtual_data
  for (let [idx, item] of list_data.slice(0, num).entries()) {
    virtual_data.value.push(Object.assign(item, {
      top: idx * list_item_height,
      height: list_item_height
    }))
  }
  // 添加滚动监听
  const list_el = document.querySelector('.list')
  list_el.addEventListener('scroll', scroll_func)
})

// 生成新的virtual_data的function
const getVirtualData = (section, index) => {
  const count = 8 // 前后各8的范围
  const result = new Array(num)
  let range = getRange(index, count)
  for (let idx = 0; idx < num; idx++) { 
    switch (range[idx]) {
      case 'mod2':
      case 'mod5':
        if (section > 0 && direction == 'up') {
          let _section = section - 1 >= 0 ? section : 0
          result[idx] = setObject(_section, idx)
        } else {
          result[idx] = setObject(section, idx)
        }
        break;
      case 'mod3':
      case 'mod4':
        if (section == 0 || direction == 'down') {
          result[idx] = setObject(section + 1, idx)
        } else {
          result[idx] = setObject(section + 1, idx)
        }
        break;
      default:
        result[idx] = setObject(section, idx)
        break;
    }
  }
  return result
}
// 取范围
const getRange = (index, count) => {
  let res = new Array(num)
  let start = index - count
  let end = index + count
  for (let idx = start; idx <= end; idx++){
    if (idx < 0) {
      res[num + idx] = 'mod2'
    } else if (idx > num - 1) {
      res[idx - num] = 'mod3'
    } else {
      res[idx] = 'mod1'
    }
  }
  if (start > 0) {
    for (let idx = 0; idx < start; idx++){
      res[idx] = res[idx] ? res[idx] : 'mod4'
    }
  }
  if (end < num - 1) {
    for (let idx = end + 1; idx < num; idx++){
      res[idx] = res[idx] ? res[idx] : 'mod5'
    }
  }
  return res
}

const setObject = (section, idx) => {
  let i = section * num + idx
  i = i < list_data.length ? i : i - list_data.length
  return Object.assign(list_data[i], {
    top: i * list_item_height,
    height: list_item_height
  })
}
</script>

<style scoped>
.list{
  max-height: 700px;
  overflow-y: auto;
  padding: 0 20px;
  position: relative;
}
.list-item{
  padding: 20px;
  border-bottom: 1px solid rgba(5, 5, 5, 0.06);
  position: absolute;
  width: calc(100% - 40px);
}
</style>